package com.ccw.string;

import java.util.Arrays;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;

/**
 * This class be used to match string by ? and *<br>
 * 1. ? match one char <br>
 * 2. * match one to more char<br>
 * 
 * @author ccwang
 * 
 */
public class SuperRegexUtils {

	private static final String PATTERN_LINE_START = "^";

	private static final String PATTERN_LINE_END = "$";

	private static final char[] META_CHARACTERS = { '$', '^', '[', ']', '(',
			')', '{', '}', '|', '+', '.', '\\' };

	/**
	 * match function, support '*' and '?'. The function is based on regex.
	 * 
	 * @param pattern
	 *            regex
	 * @param str
	 *            target string
	 * @return boolean
	 */
	public static boolean regexMatch(String pattern, String str) {
		pattern = convertToRegexPattern(pattern);
		return Pattern.matches(pattern, str);
	}

	private static String convertToRegexPattern(String wildcardString) {
		String result = PATTERN_LINE_START;
		char[] chars = wildcardString.toCharArray();
		for (char ch : chars) {
			if (Arrays.binarySearch(META_CHARACTERS, ch) >= 0) {
				result += "\\" + ch;
				continue;
			}
			switch (ch) {
			case '*':
				result += ".*";
				break;
			case '?':
				result += ".{0,1}";
				break;
			default:
				result += ch;
			}
		}
		result += PATTERN_LINE_END;
		return result;
	}

	/**
	 * only support *
	 * 
	 * @param pattern
	 *            regex
	 * @param str
	 *            target string
	 * @return boolean
	 */
	public static boolean stringMatch(String pattern, String str) {
		return wildcardMatch(pattern, str, "*");
	}

	private static boolean wildcardMatch(String pattern, String str,
			String wildcard) {
		if (StringUtils.isEmpty(pattern) || StringUtils.isEmpty(str)) {
			return false;
		}
		final boolean startWith = pattern.startsWith(wildcard);
		final boolean endWith = pattern.endsWith(wildcard);
		String[] array = StringUtils.split(pattern, wildcard);
		int currentIndex = -1;
		int lastIndex = -1;
		switch (array.length) {
		case 0:
			return true;
		case 1:
			currentIndex = str.indexOf(array[0]);
			if (startWith && endWith) {
				return currentIndex >= 0;
			}
			if (startWith) {
				return currentIndex + array[0].length() == str.length();
			}
			if (endWith) {
				return currentIndex == 0;
			}
			return str.equals(pattern);
		default:
			for (String part : array) {
				currentIndex = str.indexOf(part);
				if (currentIndex > lastIndex) {
					lastIndex = currentIndex;
					continue;
				}
				return false;
			}
			return true;
		}
	}
	
	public static void main(String[] args) {
		System.out.println(SuperRegexUtils.regexMatch("*", "toto"));
		System.out.println(SuperRegexUtils.stringMatch("*", "toto"));
		
		System.out.println(SuperRegexUtils.regexMatch("**", "toto"));
		System.out.println(SuperRegexUtils.stringMatch("**", "toto"));
		
		System.out.println(SuperRegexUtils.regexMatch("*t", "toto"));
		System.out.println(SuperRegexUtils.stringMatch("*t", "toto"));
		
		System.out.println(SuperRegexUtils.regexMatch("t*", "toto"));
		System.out.println(SuperRegexUtils.stringMatch("t*", "toto"));
		
		System.out.println(SuperRegexUtils.regexMatch("t*o", "toto"));
		System.out.println(SuperRegexUtils.stringMatch("t*o", "toto"));
		
		System.out.println(SuperRegexUtils.regexMatch("t??o", "toto"));
		System.out.println(SuperRegexUtils.stringMatch("t??o", "toto"));
	}

}
